/**
  ******************************************************************************
  * @file
  * @brief
  * @author taoye
  * @version V1.0.0
  * @date 2021/01/01
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "drv_f4_flash.h"

/* Private defines -----------------------------------------------------------*/
#define STM32_FLASH_BASE 0x08000000 	//STM32 FLASH的起始地址
 
#define FLASH_START_ADDR 0x080E0000     //最大内存0x8100000

//FLASH 扇区起始地址
#define ADDR_FLASH_SECTOR_0     ((unsigned long)0x08000000) 	//扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((unsigned long)0x08004000) 	//扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((unsigned long)0x08008000) 	//扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((unsigned long)0x0800C000) 	//扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((unsigned long)0x08010000) 	//扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((unsigned long)0x08020000) 	//扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((unsigned long)0x08040000) 	//扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((unsigned long)0x08060000) 	//扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((unsigned long)0x08080000) 	//扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((unsigned long)0x080A0000) 	//扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((unsigned long)0x080C0000) 	//扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((unsigned long)0x080E0000) 	//扇区11起始地址,128 Kbytes

/* Private Struct  -----------------------------------------------------------*/


/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/
//Pointer

//Array

//Const

/* Private function prototypes -----------------------------------------------*/

/***********************************************************************************
 * @brief 读取指定地址的半字
 * ex:
 * @par  faddr：地址
 * None
 * @par Called functions:
 * None
 * @retval 对应的数值
 **********************************************************************************/
static uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
	return *(uint32_t*)faddr;
}

/***********************************************************************************
 * @brief 获取某个地址所在的扇区
 * ex:
 * @par  addr：Flash地址
 * None
 * @par Called functions:
 * None
 * @retval 0-11 即addr所在的扇区
 **********************************************************************************/
static uint32_t STMFLASH_GetFlashSector(uint32_t addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10;

	return FLASH_Sector_11;
}
/***********************************************************************************
 * @brief FLASH 格式化多个指定区域
 * ex:
 * @par  data：数据  n：数据长度
 * None
 * @par Called functions:
 * None
 * @retval 0
 **********************************************************************************/
static int FLASH_Erase( drv_flash_t *this, uint32_t WriteAddr, uint32_t len)
{
	FLASH_Status status = FLASH_COMPLETE;
	uint32_t addrx = 0;
	uint32_t endaddr = 0;
	if(WriteAddr < STM32_FLASH_BASE || WriteAddr%4 )   //非法地址
	{
		return 0;
	}

	FLASH_ClearFlag( FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR | FLASH_FLAG_RDERR);

	FLASH_Unlock();                     //解锁
	FLASH_DataCacheCmd(DISABLE);        //FLASH擦除期间,必须禁止数据缓存

	addrx = WriteAddr;				          //写入的起始地址
	endaddr = WriteAddr + len;	              //写入的结束地址
	if(addrx<0X1FFF0000)			          //只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<endaddr)		          //扫清一切障碍.(对非0xFFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF) //有0XFFFFFFFF的地方,要擦除这个扇区
			{
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!
				if(status!=FLASH_COMPLETE)break;	//发生错误了
			}else addrx+=4;
		}
	}

	FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开始数据缓存
	FLASH_Lock();//上锁

    if(status != FLASH_COMPLETE){
        return -1;
    }

	return 0;
}

 /***********************************************************************************
 * @brief FLASH 写函数
 * ex:
 * @par  data：数据  n：数据长度
 * None
 * @par Called functions:
 * None
 * @retval 0
 **********************************************************************************/
static int FLASH_WRITE( drv_flash_t *this, uint32_t WriteAddr,uint8_t *data,uint32_t len)
{
	uint32_t memory_data;
	uint32_t memory_addr;
	uint32_t count = 0;
	uint8_t ii = 0;
	FLASH_Status status = FLASH_COMPLETE;

	FLASH_Unlock();
	FLASH_DataCacheCmd(DISABLE);                          //FLASH擦除期间,必须禁止数据缓存

	memory_addr = WriteAddr;
	while(memory_addr < (WriteAddr + len))		      //扫清一切障碍.(对非0xFFFFFFFF的地方,先擦除)
	{
		if(STMFLASH_ReadWord(memory_addr) != 0XFFFFFFFF)    //有0XFFFFFFFF的地方,要擦除这个扇区
		{
			status = FLASH_EraseSector(STMFLASH_GetFlashSector(memory_addr),VoltageRange_3);//VCC=2.7~3.6V之间!!
			if(status != FLASH_COMPLETE)break;	              //发生错误
		}else memory_addr += 4;
	}

	if(status == FLASH_COMPLETE)
	{
		memory_addr = WriteAddr;
		while(count < len)
		{
			memory_data = data[count];
			memory_data += data[count+1]<<8;
			memory_data += data[count+2]<<16;
			memory_data += data[count+3]<<24;
			status = FLASH_ProgramWord(memory_addr+count,memory_data);
			if(status != FLASH_COMPLETE)//写入数据
			{
				break;	//写入异常
			}
			count+=4;
			if((len-count) < 4)break;
		}
		if(len%4 != 0 && status == FLASH_COMPLETE)
		{
			memory_data = 0;
			for(;ii< (len-count);ii++)
			{
				memory_data += (uint32_t)data[count]<<(8*ii);
			}
			status = FLASH_ProgramWord(memory_addr+count,memory_data);
		}
	}
	FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开始数据缓存
	FLASH_Lock();

    if(status != FLASH_COMPLETE){
        return -1;
    }

    return 0;
}

/***********************************************************************************
 * @brief FLASH 读数据
 * ex:
 * @par  data 读取的数据 ,len为读取长度
 * None
 * @par Called functions:
 * None
 * @retval
 **********************************************************************************/
static int FLASH_READ( drv_flash_t *this, uint32_t ReadAddr,uint8_t *data,uint32_t len)
{
	//unsigned short int len;
	unsigned int memory_data;
	unsigned int memory_addr;
	unsigned int count = 0;

	memory_addr = ReadAddr;

	while(count < len)
	{
		memory_data = *(unsigned int *)(memory_addr + count);
		memcpy(data+count,(unsigned char *)&memory_data,4);
		count += 4;
		if((len - count) < 4)break;
	}
	if(len%4 != 0)
	{
		memory_data = *(unsigned int *)(memory_addr + count);
		memcpy(data+count,(unsigned char *)&memory_data,len - count);
	}

	return 0;
}

/***********************************************************************************
 * @brief 功能说明：设置MCU Flash读写擦除函数
 * ex:
 * @par   输入参数：drv_flash_t *this - 内部flash操作函数
 *        输出参数：drv_flash_t *this - 内部flash操作函数
 * None
 * @par
 * None
 * @retval 返回值：无
 **********************************************************************************/
int Drv_Flash_Init( drv_flash_t *this )
{
    this->Read  = FLASH_READ;
    this->Write = FLASH_WRITE;
    this->Erase = FLASH_Erase;
	return 0;
}
